﻿// ===============================================================================
//  Copyright © ymind.net. All rights reserved .
//  官方网站：http://ymind.net/
//  版权所有：彦铭工作室 老陈出品
// ===============================================================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;

namespace Lcsoft.TemplateEngine.Core
{
	/// <summary>
	/// 表示一个语言包。
	/// </summary>
	[ComVisible(true)]
	[Serializable]
	public struct LanguagePack : IEquatable<LanguagePack>
	{
		private static readonly bool _emptyValueFilled;

		/// <summary>
		/// 表示空语言包。此字段为只读。
		/// </summary>
		public static readonly LanguagePack Empty;

		/// <summary>
		/// 初始化语言包的默认值。
		/// </summary>
		static LanguagePack()
		{
			Empty = new LanguagePack(String.Empty);
			_emptyValueFilled = true;
		}

		/// <summary>
		/// 初始化语言包。
		/// </summary>
		/// <param name="code">指定包含语言类型代码的字符串。</param>
		public LanguagePack(string code) : this()
		{
			if (_emptyValueFilled)
			{
				if (code == null) throw new ArgumentNullException("code");
				if (code.Length == 0) throw new ArgumentOutOfRangeException("code");
			}

			this.Code = code;
			this.Items = new HashSet<LanguageItem>();
		}

		/// <summary>
		/// 获取该语言包中具有指定名称的语言项。
		/// </summary>
		/// <param name="langName">指定语言项的名称。</param>
		/// <returns>如果当前语言包包含具有指定名称的语言项则返回其实例，否则返回 <see cref="LanguageItem.Empty"/>。</returns>
		public LanguageItem this[string langName]
		{
			get
			{
				var list = this.Items.Where(item => item.Name == langName).ToList();

				return list.Count == 0 ? LanguageItem.Empty : list.First();
			}
		}

		/// <summary>
		/// 获取或设置当前语言包的语言代码。
		/// </summary>
		public string Code { get; private set; }

		/// <summary>
		/// 获取所有可用的语言项的实例集合。
		/// </summary>
		public HashSet<LanguageItem> Items { get; private set; }

		#region IEquatable<LanguagePack> Members

		/// <summary>
		/// 返回一个值，该值指示此实例是否与指定的对象相等。
		/// </summary>
		/// <param name="other">要与此实例进行比较的对象。</param>
		/// <returns>如果 <paramref name="other"/> 是 <see cref="LanguagePack"/> 的实例并且等于此实例的值，则为 true；否则为 false。</returns>
		public bool Equals(LanguagePack other) { return Equals(other.Code, this.Code); }

		#endregion

		/// <summary>
		/// 在当前语言包中添加一个新的语言项。
		/// </summary>
		/// <param name="name">指定语言项的名称。</param>
		/// <param name="value">指定语言项的内容。</param>
		/// <returns>返回对所添加的 <see cref="LanguageItem"/> 的实例的引用。</returns>
		public LanguageItem AddItem(string name, string value) { return this.AddItem(this.CreateItem(name, value)); }

		/// <summary>
		/// 在当前语言包中添加一个新的语言项。
		/// </summary>
		/// <param name="item"></param>
		/// <returns>返回对所添加的 <see cref="LanguageItem"/> 的实例的引用。</returns>
		public LanguageItem AddItem(LanguageItem item)
		{
			this.Items.Add(item);

			return item;
		}

		/// <summary>
		/// 在当前语言包中创建一个新的语言项。
		/// </summary>
		/// <param name="name">指定语言项的名称。</param>
		/// <param name="value">指定语言项的内容。</param>
		/// <returns>返回对所创建的 <see cref="LanguageItem"/> 的实例的引用。</returns>
		public LanguageItem CreateItem(string name, string value) { return new LanguageItem(name, value, this); }

		/// <summary>
		/// 返回一个值，该值指示此实例是否与指定的对象相等。
		/// </summary>
		/// <param name="obj">要与此实例进行比较的对象。</param>
		/// <returns>如果 <paramref name="obj"/> 是 <see cref="LanguagePack"/> 的实例并且等于此实例的值，则为 true；否则为 false。</returns>
		public override bool Equals(object obj)
		{
			if (ReferenceEquals(null, obj)) return false;

			return obj is LanguagePack && this.Equals((LanguagePack)obj);
		}

		/// <summary>
		/// 返回此实例的哈希代码。
		/// </summary>
		/// <returns>32 位有符号整数哈希代码。</returns>
		public override int GetHashCode() { return (this.Code != null ? this.Code.GetHashCode() : 0); }

		/// <summary>
		/// 确定 <see cref="LanguagePack"/> 的两个指定的实例是否相等。
		/// </summary>
		/// <param name="left">第一个 <see cref="LanguagePack"/> 的实例。</param>
		/// <param name="right">第二个 <see cref="LanguagePack"/> 的实例。</param>
		/// <returns>如果 <paramref name="left"/> 和 <paramref name="right"/> 表示同一语言包，则为 true；否则为 false。</returns>
		public static bool operator ==(LanguagePack left, LanguagePack right) { return left.Equals(right); }

		/// <summary>
		/// 确定 <see cref="LanguagePack"/> 的两个指定的实例是否不等。
		/// </summary>
		/// <param name="left">第一个 <see cref="LanguagePack"/> 的实例。</param>
		/// <param name="right">第二个 <see cref="LanguagePack"/> 的实例。</param>
		/// <returns>如果 <paramref name="left"/> 和 <paramref name="right"/> 不表示同一语言包，则为 true；否则为 false。</returns>
		public static bool operator !=(LanguagePack left, LanguagePack right) { return !left.Equals(right); }

		/// <summary>
		/// 将当前 <see cref="LanguagePack"/> 对象的值转换为其等效的字符串表示形式。
		/// </summary>
		/// <returns>当前 <see cref="LanguagePack"/> 对象的值的字符串表示形式。</returns>
		public override string ToString() { return this.Code; }
	}
}
